# @Time : 2025-01-08 10:07
# @Author : Fioman 
# @Phone : 13149920693
import threading
from typing import List

import app_config
from common.exception_helper import error_handler_produce
from common.file_dir_helper import create_dir_by_order
from common.produce_logger import debug_produce
from db_tool.db_config import TableName
from db_tool.db_handler import DbHandler
from web_tool.produce_data_model import ProduceDataType

"""
设备状态类
"""

db = DbHandler()


class DeviceStateBase:
    """
    设备状态基类
    """

    def __init__(self):
        self.isOnline = False
        self.isRun = False
        self.isRs = False
        self.isPause = False


class DeviceState:
    """
    设备状态,全局唯一状态,所以使用类变量即可,不用声明对象.
    """
    # 创建单例设备状态类,线程安全的
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            with cls._lock:
                cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        if not hasattr(self, '_initialized'):
            self.cutPlcState: DeviceStateBase = DeviceStateBase()
            self.cameraGroupState: List[bool] = [False, False]
            self.orderUsedId = None  # 一开始的orderUsedId 为None,检测其是否变化
            self.totalWipCount = 0  # 设备内产品数量
            # 为WIP计数增减操作添加独立锁,确保多线程安全
            self._wipLock = threading.Lock()
            self.realod_working_info()
            create_dir_by_order(self.orderUsedId)
            self._initialized = True
            debug_produce("in DeviceState.__init__(),设备状态初始化完成")

    def realod_working_info(self):
        """
        加载当前作业的工作信息,主要是当前作业的工单的key和id,还有一些其他的信息
        """
        result = db.get_data_one(TableName.workingInfos, {"key": "1"})
        if result.state:
            data = result.data
        else:
            data = {}

        self.orderUsedKey = data.get("orderUsedKey", "default")
        # 检测这个orderUsedKey是否在数据库中存在,如果不存在,就使用totalOrders的第一个作为当前
        # 的orderUsed.
        query = {"key": self.orderUsedKey}
        result = db.get_data_one(TableName.orders, query)
        if not result.state:
            result = db.get_data_list(TableName.orders)
            if len(result.data) > 0:
                data = result.data[0]
                orderUsedKey = data.get("key", "default")
                orderId = data.get("orderId", "default")
                query = {"key": "1"}
                newValues = {"orderUsedKey": orderUsedKey, "orderUsedId": orderId}
                db.update_data(TableName.workingInfos, query, newValues)
                return self.realod_working_info()
        orderUsedId = data.get("orderUsedId", "default")
        lotIdUsed = data.get("lotIdUsed", "default")
        from eap_control import eap_request, resp_parse
        from eap_control.eap_config import EapConfig
        ec = EapConfig()
        if self.orderUsedId is not None and orderUsedId != self.orderUsedId:
            opModeToEap = ec.get_operation_mode_code(ec.operation_mode)
            resp = eap_request.request_equipment_information(opModeToEap, orderUsedId,
                                                             ec.lineCleaning)
            resp_parse.parse_equipment_information_response("EquipmentInformation", resp)
            # 工单更换之后,这里的数量也被置位0
            self.totalWipCount = 0
        self.orderUsedId = orderUsedId
        self.lotIdUsed = lotIdUsed  # 使用的批次ID
        self.workIndex = data.get("workIndex", 0)
        self.finishedCount = data.get("finishedCount", 0)
        self.indexMax = data.get("indexMax", 0)
        self.activateCode = data.get("activateCode", "zysz168")
        self.lockDateTime = data.get("lockDateTime", "")
        create_dir_by_order(self.orderUsedId)
        ec.pn_name = self.orderUsedId  # 料号
        ec.process_name = self.lotIdUsed  # 批次ID
        ec.panel_id = self.workIndex  # 板子Id
        debug_produce(f"workingInfos 加载完成: {data}")

    @error_handler_produce
    def update_finished_val(self):
        """
        将数据更新到当前批号
        """
        query = {
            "key": self.orderUsedKey
        }
        orderRes = db.get_data_one(TableName.orders, query)
        if not orderRes.state:
            debug_produce(orderRes.info)
            return orderRes.data
        orderData = orderRes.data
        newCount = orderData.get("finished", 0) + 1
        newData = {"finished": newCount}
        db.update_data(TableName.orders, query, newData)
        db.update_produce_record(1)
        from web_tool.send_to_web_handler import update_produce_model_in_web
        update_produce_model_in_web(ProduceDataType.workingOrder)
        # 这里要递增一下,设备内产品数量
        with self._wipLock:
            self.totalWipCount += 1
        # 然后过20秒之后,将这个数量减少1,并且数量不允许为负
        timer = threading.Timer(25.0, self._decrement_wip_count_safe)
        timer.daemon = True  # 守护线程,不阻塞进程退出
        timer.start()
        from eap_control.eap_config import EapConfig
        ec = EapConfig()
        ec.pn_name = self.orderUsedId  # 料号
        ec.process_name = self.lotIdUsed  # 批次ID
        ec.panel_id = self.workIndex  # 板子Id
        # 上报单片数据, 第一个0表示单片数据上报 ,第二个1表示OK
        ec.process_data_report("0", "1")

    def _decrement_wip_count_safe(self):
        """
        延迟回调: 安全地将设备内产品数量减少1,并做下限保护。
        """
        try:
            with self._wipLock:
                newVal = self.totalWipCount - 1
                if newVal < 0:
                    newVal = 0
                self.totalWipCount = newVal
        except Exception as e:
            # 异常保护,不影响主流程
            debug_produce(f"_decrement_wip_count_safe error: {e}")

    def to_dict(self):
        return {
            "cutPlcState": {
                "isOnline": self.cutPlcState.isOnline,
                "isRun": self.cutPlcState.isRun,
                "isRs": self.cutPlcState.isRs
            },
            "cameraGroupState": self.cameraGroupState,
            "workStopState": app_config.workStopState
        }
